package com.srmt.common.ratelimit.impl;

import com.srmt.common.ratelimit.RateLimiter;
import com.srmt.common.ratelimit.config.ApiEndpoint;
import com.srmt.common.ratelimit.config.RateLimitConfig;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 基于Google Guava的高精度限流器实现
 * 
 * 特点：
 * - 极高的精度（微秒级）
 * - 经过Google大规模验证
 * - 简单可靠的API
 * - 适用于本地单机场景
 * 
 * @author SRMT Development Team
 * @since 1.6.0
 */
public class GuavaRateLimiter implements RateLimiter {
    
    private static final Logger logger = LoggerFactory.getLogger(GuavaRateLimiter.class);
    
    /**
     * Guava限流器存储
     * key: API标识
     * value: Guava RateLimiter实例
     */
    private final Map<String, com.google.common.util.concurrent.RateLimiter> limiters;
    
    /**
     * 配置
     */
    private final RateLimitConfig config;
    
    /**
     * 是否已关闭
     */
    private volatile boolean shutdown = false;
    
    /**
     * 构造函数
     * 
     * @param config 限流配置
     */
    public GuavaRateLimiter(RateLimitConfig config) {
        if (config == null) {
            throw new IllegalArgumentException("限流配置对象不能为null");
        }
        
        this.config = config;
        this.limiters = new ConcurrentHashMap<>();
        
        logger.info("[Guava] 限流器已使用默认QPS初始化: {}", config.getDefaultQps());
    }
    
    @Override
    public boolean tryAcquire(String api, long timeout) {
        if (shutdown) {
            logger.warn("[Guava] 限流器 is shutdown, rejecting request for API: {}", api);
            return false;
        }
        
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        
        boolean acquired;
        if (timeout <= 0) {
            // 立即尝试，不等待
            acquired = limiter.tryAcquire();
            if (!acquired) {
                logger.debug("[Guava] API: {} - No permit available immediately (QPS: {})", 
                           api, limiter.getRate());
            }
        } else {
            // 带超时的尝试
            acquired = limiter.tryAcquire(timeout, TimeUnit.MILLISECONDS);
            if (!acquired) {
                logger.warn("[Guava] API: {} - 获取许可失败 within {}ms (QPS: {})", 
                           api, timeout, limiter.getRate());
            }
        }
        
        if (acquired) {
            logger.trace("[Guava] API: {} - Permit acquired", api);
        }
        
        return acquired;
    }
    
    @Override
    public void acquire(String api) throws InterruptedException {
        if (shutdown) {
            throw new InterruptedException("限流器 is shutdown");
        }
        
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        
        // Guava的acquire()会阻塞直到获取到令牌
        // 它会自动计算需要等待的时间
        double waitTime = limiter.acquire();
        
        if (waitTime > 0.01) { // 如果等待时间超过10ms，记录日志
            logger.debug("[Guava] API: {} - Acquired permit after {:.2f} seconds wait", api, waitTime);
        } else {
            logger.trace("[Guava] API: {} - Acquired permit immediately", api);
        }
        
        // 检查中断状态
        if (Thread.interrupted()) {
            throw new InterruptedException("等待许可时被中断");
        }
    }
    
    @Override
    public void setQps(String api, int qps) {
        if (qps <= 0) {
            throw new IllegalArgumentException("QPS必须为正数,当前值: " + qps);
        }
        
        // Guava RateLimiter支持动态调整速率
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        double oldRate = limiter.getRate();
        limiter.setRate(qps);
        
        logger.info("[Guava] API: {} - QPS updated from {} to {}", api, oldRate, qps);
    }
    
    @Override
    public int getQps(String api) {
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        return (int) limiter.getRate();
    }
    
    @Override
    public int getAvailablePermits(String api) {
        // Guava RateLimiter不直接提供可用令牌数的查询
        // 我们可以通过tryAcquire(0)来判断是否有令牌可用
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        
        // 尝试获取令牌但不等待，如果成功说明至少有1个令牌
        // 注意：这会消耗一个令牌
        if (limiter.tryAcquire()) {
            // 如果获取成功，说明至少有1个令牌
            // 由于我们消耗了一个，实际可用数可能更多
            // 但Guava不提供精确查询，返回1作为近似值
            return 1;
        }
        return 0;
    }
    
    @Override
    public void reset(String api) {
        if (api == null) {
            // 重置所有限流器
            limiters.clear();
            logger.info("[Guava] Reset all rate limiters");
        } else {
            // 重置特定API的限流器
            // Guava不支持重置，我们通过移除并重新创建来实现
            limiters.remove(api);
            logger.info("[Guava] Reset rate limiter for API: {}", api);
        }
    }
    
    @Override
    public void shutdown() {
        shutdown = true;
        limiters.clear();
        logger.info("[Guava] 限流器 shutdown complete");
    }
    
    /**
     * 获取或创建限流器
     * 
     * @param api API标识
     * @return Guava RateLimiter实例
     */
    private com.google.common.util.concurrent.RateLimiter getLimiter(String api) {
        return limiters.computeIfAbsent(api, k -> {
            int qps = config.getApiQps(api);
            
            // 检查是否有预定义的端点
            ApiEndpoint endpoint = ApiEndpoint.fromCode(api);
            if (endpoint != null && qps == config.getDefaultQps()) {
                qps = endpoint.getDefaultQps();
            }
            
            // 创建Guava RateLimiter
            // 使用create方法创建一个平滑突发限流器(SmoothBursty)
            com.google.common.util.concurrent.RateLimiter rateLimiter = 
                com.google.common.util.concurrent.RateLimiter.create(qps);
            
            logger.info("[Guava] 为API创建限流器: {}, QPS: {}", api, qps);
            return rateLimiter;
        });
    }
    
    /**
     * 获取详细的限流器信息（用于调试和监控）
     * 
     * @param api API标识
     * @return 限流器信息
     */
    public RateLimiterInfo getInfo(String api) {
        com.google.common.util.concurrent.RateLimiter limiter = getLimiter(api);
        return new RateLimiterInfo(
            api,
            (int) limiter.getRate(),
            limiter.tryAcquire() ? "Available" : "Exhausted"
        );
    }
    
    /**
     * 限流器信息
     */
    public static class RateLimiterInfo {
        private final String api;
        private final int qps;
        private final String status;
        
        public RateLimiterInfo(String api, int qps, String status) {
            this.api = api;
            this.qps = qps;
            this.status = status;
        }
        
        public String getApi() {
            return api;
        }
        
        public int getQps() {
            return qps;
        }
        
        public String getStatus() {
            return status;
        }
        
        @Override
        public String toString() {
            return String.format("RateLimiterInfo{api='%s', qps=%d, status='%s'}", 
                               api, qps, status);
        }
    }
}